#ifndef __TIMER__
#define __TIMER__

#include<iostream>
#include<queue>
#include<mutex>
#include<thread>
#include<functional>
#include<atomic>
#include<chrono>
#include<condition_variable>

#include"mtx_hashmap.hpp"
#include"threadpool.hpp"

//定时器的管理类
class TimerQueue
{
public:
    //定时器节点
    struct TimerNode
    {
        int _timer_node_id;                                 //节点id                          

        bool _timer_node_is_repeated{false};                //节点是否重复执行
        bool _timer_node_is_period{false};                  //节点是否周期执行

        int _timer_node_repeated_id;                        //节点重复执行id
        int _timer_node_repeated_num;                       //节点重复执行数量

        std::chrono::milliseconds _timer_node_period_time;  //节点周期执行时间

        std::chrono::time_point<std::chrono::high_resolution_clock> _timer_node_timepoint;
                                                            //节点执行的精确时间

        std::function<void()> _timer_node_callback;         //节点执行的任务

        //重载<：时间大的人，后执行
        bool operator<(const TimerNode& tn)const
        {
            return _timer_node_timepoint>tn._timer_node_timepoint;
        }
    };

    //节点状态
    enum class NodeState
    {
        Running = 0
    };

public:
    TimerQueue() = default;

    //运行定时器，创造时钟线程
    void run()
    {
        _timer_tick_thread=std::thread([this](){run_local();});
    }

    //加入节点，节点无特殊属性
    template<typename Fun,typename... Args>
    int add_node(const std::chrono::time_point<std::chrono::high_resolution_clock>& time_point,Fun&& f,Args&&... args)
    {
        //设置节点属性，并加入队列
        TimerNode task;
        task._timer_node_id=_timer_id.fetch_add(1);
        task._timer_node_is_period=false;
        task._timer_node_timepoint=time_point;
        task._timer_node_callback=std::bind(std::forward<Fun>(f),std::forward<Args>(args)...);
        
        _timer_node_state.insert(task._timer_node_id,NodeState::Running);
        std::unique_lock<std::mutex> mtx(_timer_mutex);
        _timer_queue.push(task);
        _timer_cond.notify_all();

        return task._timer_node_id;
    }

    //加入节点，节点是否周期轮转由is_period决定
    template<typename Fun,typename... Args>
    int add_node_period(int ms_time,bool is_period,Fun&& f,Args&&... args)
    {
        TimerNode task;
        task._timer_node_id=_timer_id.fetch_add(1);
        task._timer_node_is_period=is_period;
        task._timer_node_period_time=std::chrono::milliseconds(ms_time);
        task._timer_node_timepoint=std::chrono::high_resolution_clock::now()+task._timer_node_period_time;
        task._timer_node_callback=std::bind(std::forward<Fun>(f),std::forward<Args>(args)...);
        
        _timer_node_state.insert(task._timer_node_id,NodeState::Running);
        std::unique_lock<std::mutex> mtx(_timer_mutex);
        _timer_queue.push(task);
        _timer_cond.notify_all();

        return task._timer_node_id;
    }

    //加入节点，节点重复执行，重复次数由repeated_num决定
    template<typename Fun,typename... Args>
    int add_node_repeated(int ms_time,int repeated_num,Fun&& f,Args&&... args)
    {
        TimerNode task;
        task._timer_node_id=_timer_id.fetch_add(1);
        task._timer_node_period_time=std::chrono::milliseconds(ms_time);
        task._timer_node_is_repeated=true;
        task._timer_node_repeated_num=repeated_num;
        task._timer_node_timepoint=std::chrono::high_resolution_clock::now()+task._timer_node_period_time;
        task._timer_node_callback=std::bind(std::forward<Fun>(f),std::forward<Args>(args)...);
        
        _timer_node_state.insert(task._timer_node_id,NodeState::Running);
        std::unique_lock<std::mutex> mtx(_timer_mutex);
        _timer_queue.push(task);
        _timer_cond.notify_all();

        return task._timer_node_id;
    }

    //删除节点
    void cancel_node(int id)
    {
        if(_timer_node_state.count(id))_timer_node_state.erase(id);
    }

    //判断线程池是否有空闲线程
    bool is_available()
    {
        return _timer_threadpool.get_idle_thread_num()>=0;
    }

    //获取队列大小
    int size()
    {
        return _timer_queue.size();
    }

    ~TimerQueue()
    {
        _timer_running.store(false);
        _timer_cond.notify_all();
        //主线程等待时钟线程退出再退出
        if(_timer_tick_thread.joinable())_timer_tick_thread.join();
    }

private:
    //单独运行的时钟线程，循环判断队列中的任务是否执行，若执行，将任务加入线程池
    void run_local()
    {
        while(_timer_running.load())
        {
            std::unique_lock<std::mutex> mtx(_timer_mutex);
            //若队列为空，线程等待
            if(_timer_queue.empty())
            {
                _timer_cond.wait(mtx);
                continue;
            }

            //获得队列顶部任务，计算任务还有多久执行
            //若时间>0，线程等待相应时间；若时间<=0，
            auto task=_timer_queue.top();
            auto diff_time=task._timer_node_timepoint-std::chrono::high_resolution_clock::now();
            if(std::chrono::duration_cast<std::chrono::milliseconds>(diff_time).count()>0)
            {
                _timer_cond.wait_for(mtx,diff_time);
                continue;
            }
            else
            {
                _timer_queue.pop();
                //判断节点是否还要执行，不执行，则只弹出节点；执行，则根据节点特性，执行任务
                if(!_timer_node_state.count(task._timer_node_id))continue;
                //若节点为周期执行，则将节点时间更新，重新加入队列
                if(task._timer_node_is_period)
                {
                    task._timer_node_timepoint=std::chrono::high_resolution_clock::now()+task._timer_node_period_time;
                    _timer_queue.push(task);
                }
                //若节点为重复执行，则将节点时间更新，重新加入队列，重复数量减一
                if(task._timer_node_is_repeated&&task._timer_node_repeated_num>0)
                {
                    task._timer_node_timepoint=std::chrono::high_resolution_clock::now()+task._timer_node_period_time;
                    task._timer_node_repeated_num--;
                    _timer_queue.push(task);
                }
                mtx.unlock();
                // 将任务加入线程池，执行任务,因为已经绑定参数，所以不需要传入参数
                _timer_threadpool.post_task(std::move(task._timer_node_callback));
            }
        }
    }

private:
    std::atomic<int> _timer_id{0};              //下一个定时器的id
    std::atomic<bool> _timer_running{true};     //timer的运行状态

    std::priority_queue<TimerNode> _timer_queue;//定时器队列
    HashMap<int,NodeState> _timer_node_state;   //存放节点状态的哈希表

    std::thread _timer_tick_thread;             //时钟线程
    Threadpool _timer_threadpool;               //定时器存放执行任务线程和时钟线程的线程池

    std::mutex _timer_mutex;
    std::condition_variable _timer_cond;
};


class TimerWheel
{

};

#endif